// Copyright 2008 Silvio Massari
//
// This file is part of SilvioMassari.Automata
//
// SilvioMassari.Automata is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// SilvioMassari.Automata is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with SilvioMassari.Automata.  If not, see <http://www.gnu.org/licenses/>.
				
using System;
using System.Text;
using System.Collections.Generic;
using NUnit.Core;
using NUnit.Framework;

using SilvioMassari.Automata;

namespace SilvioMassari.Automata.Test
{
    [TestFixture]
    public class NdaUT
    {
        public NdaUT()
        {
        }

        [Test]
        public void New()
        {
			Nda<char, int> nda = new Nda<char, int>();
            Assert.IsNotNull(nda);
            Assert.IsFalse(nda.Process((string)null));
            Assert.IsFalse(nda.Process(string.Empty));
            Assert.IsFalse(nda.Process("a"));
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void PatternEmpty()
        {
            Nda<char, int> nda = new Nda<char, int>();
            Assert.IsNotNull(nda);
            nda.AddPattern(string.Empty, 1);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void PatternNull()
        {
            Nda<char, int> nda = new Nda<char, int>();
            Assert.IsNotNull(nda);
			nda.AddPattern((string)null, 1);
        }

        [Test]
        public void Char()
        {
            Nda<char, int> nda = new Nda<char, int>();
            nda.AddPattern("a", 1);
			Assert.IsFalse(nda.Process((string)null));
            Assert.IsFalse(nda.Process(string.Empty));
            Assert.IsFalse(nda.Process("b"));
            Assert.IsFalse(nda.Process("aa"));
            Assert.IsFalse(nda.Process("ab"));
            Assert.IsFalse(nda.Process("ba"));
            Assert.IsTrue(nda.Process("a"));
            Assert.AreEqual(1, nda.Value);
        }

        [Test]
        public void And()
        {
            Nda<char, int> nda = new Nda<char, int>();
            nda.AddPattern("ab", 1);
            Assert.IsFalse(nda.Process((string)null));
            Assert.IsFalse(nda.Process(string.Empty));
            Assert.IsFalse(nda.Process("a"));
            Assert.IsFalse(nda.Process("b"));
            Assert.IsFalse(nda.Process("ba"));
            Assert.IsFalse(nda.Process("cab"));
            Assert.IsFalse(nda.Process("abc"));
            Assert.IsFalse(nda.Process("ba"));
            Assert.IsTrue(nda.Process("ab"));
            Assert.AreEqual(1, nda.Value);
        }

        [Test]
        public void And2()
        {
            Nda<char, int> nda = new Nda<char, int>();
            nda.AddPattern("bb", 1);
            Assert.IsFalse(nda.Process((string)null));
            Assert.IsFalse(nda.Process(string.Empty));
            Assert.IsFalse(nda.Process("a"));
            Assert.IsFalse(nda.Process("b"));
            Assert.IsFalse(nda.Process("bbb"));
            Assert.IsFalse(nda.Process("abba"));
            Assert.IsFalse(nda.Process("abb"));
            Assert.IsFalse(nda.Process("bba"));
            Assert.IsTrue(nda.Process("bb"));
            Assert.AreEqual(1, nda.Value);
        }

        [Test]
        public void Or()
        {
            Nda<char, int> nda = new Nda<char, int>();
            nda.AddPattern("a|b", 1);
            Assert.IsFalse(nda.Process((string)null));
            Assert.IsFalse(nda.Process(string.Empty));
            Assert.IsFalse(nda.Process("ba"));
            Assert.IsFalse(nda.Process("cab"));
            Assert.IsFalse(nda.Process("abc"));
            Assert.IsFalse(nda.Process("ba"));
            Assert.IsFalse(nda.Process("ab"));
            Assert.IsFalse(nda.Process("c"));
            Assert.IsTrue(nda.Process("a"));
            Assert.AreEqual(1, nda.Value);
            Assert.IsTrue(nda.Process("b"));
            Assert.AreEqual(1, nda.Value);
        }

        [Test]
        public void Many()
        {
            Nda<char, int> nda = new Nda<char, int>();
            nda.AddPattern("a*", 1);
            Assert.IsFalse(nda.Process("ba"));
            Assert.IsFalse(nda.Process("cab"));
            Assert.IsFalse(nda.Process("abc"));
            Assert.IsFalse(nda.Process("ba"));
            Assert.IsFalse(nda.Process("ab"));
            Assert.IsFalse(nda.Process("c"));
            Assert.IsTrue(nda.Process("a"));
            Assert.AreEqual(1, nda.Value);
            Assert.IsTrue(nda.Process("aa"));
            Assert.AreEqual(1, nda.Value);
            Assert.IsTrue(nda.Process(string.Empty));
            Assert.AreEqual(1, nda.Value);
            Assert.IsTrue(nda.Process((string)null));
            Assert.AreEqual(1, nda.Value);
        }

        [Test]
        public void ManyOr()
        {
            Nda<char, int> nda = new Nda<char, int>();
            nda.AddPattern("a*|b", 1);
            Assert.IsFalse(nda.Process("ba"));
            Assert.IsFalse(nda.Process("cab"));
            Assert.IsFalse(nda.Process("abc"));
            Assert.IsFalse(nda.Process("ba"));
            Assert.IsFalse(nda.Process("aab"));
            Assert.IsFalse(nda.Process("c"));
            Assert.IsTrue(nda.Process("b"));
            Assert.AreEqual(1, nda.Value);
            Assert.IsTrue(nda.Process("a"));
            Assert.AreEqual(1, nda.Value);
            Assert.IsTrue(nda.Process("aa"));
            Assert.AreEqual(1, nda.Value);
            Assert.IsTrue(nda.Process("aaa"));
            Assert.AreEqual(1, nda.Value);
            Assert.IsTrue(nda.Process(string.Empty));
            Assert.AreEqual(1, nda.Value);
            Assert.IsTrue(nda.Process((string)null));
            Assert.AreEqual(1, nda.Value);
        }

        [Test]
        public void ManyAnd()
        {
            Nda<char, int> nda = new Nda<char, int>();
            nda.AddPattern("a*b", 1);
            Assert.IsFalse(nda.Process(string.Empty));
            Assert.IsFalse(nda.Process((string)null));
            Assert.IsFalse(nda.Process("ba"));
            Assert.IsFalse(nda.Process("cab"));
            Assert.IsFalse(nda.Process("abc"));
            Assert.IsFalse(nda.Process("bbbba"));
            Assert.IsFalse(nda.Process("a"));
            Assert.IsFalse(nda.Process("aa"));
            Assert.IsFalse(nda.Process("c"));
            Assert.IsTrue(nda.Process("b"));
            Assert.AreEqual(1, nda.Value);
            Assert.IsTrue(nda.Process("ab"));
            Assert.AreEqual(1, nda.Value);
            Assert.IsTrue(nda.Process("aab"));
            Assert.AreEqual(1, nda.Value);
        }

        [Test]
        public void AndOr()
        {
            Nda<char, int> nda = new Nda<char, int>();
            nda.AddPattern("ab|c", 1);
            Assert.IsFalse(nda.Process(string.Empty));
            Assert.IsFalse(nda.Process((string)null));
            Assert.IsFalse(nda.Process("ac"));
            Assert.IsFalse(nda.Process("bc"));
            Assert.IsFalse(nda.Process("abc"));
            Assert.IsFalse(nda.Process("ba"));
            Assert.IsFalse(nda.Process("x"));
            Assert.IsTrue(nda.Process("ab"));
            Assert.AreEqual(1, nda.Value);
            Assert.IsTrue(nda.Process("c"));
            Assert.AreEqual(1, nda.Value);
        }

        [Test]
        public void AndMany()
        {
            Nda<char, int> nda = new Nda<char, int>();
            nda.AddPattern("ab*", 1);
            Assert.IsFalse(nda.Process(string.Empty));
            Assert.IsFalse(nda.Process((string)null));
            Assert.IsFalse(nda.Process("aba"));
            Assert.IsFalse(nda.Process("b"));
            Assert.IsFalse(nda.Process("bb"));
            Assert.IsFalse(nda.Process("aab"));
            Assert.IsFalse(nda.Process("aa"));
            Assert.IsTrue(nda.Process("a"));
            Assert.AreEqual(1, nda.Value);
            Assert.IsTrue(nda.Process("ab"));
            Assert.AreEqual(1, nda.Value);
            Assert.IsTrue(nda.Process("abb"));
            Assert.AreEqual(1, nda.Value);
        }

        [Test]
        public void OrAnd()
        {
            Nda<char, int> nda = new Nda<char, int>();
            nda.AddPattern("a|bc", 1);
            Assert.IsFalse(nda.Process(string.Empty));
            Assert.IsFalse(nda.Process((string)null));
            Assert.IsFalse(nda.Process("ab"));
            Assert.IsFalse(nda.Process("ac"));
            Assert.IsFalse(nda.Process("abc"));
            Assert.IsFalse(nda.Process("cb"));
            Assert.IsFalse(nda.Process("x"));
            Assert.IsTrue(nda.Process("a"));
            Assert.AreEqual(1, nda.Value);
            Assert.IsTrue(nda.Process("bc"));
            Assert.AreEqual(1, nda.Value);
        }

        [Test]
        public void OrMany()
        {
            Nda<char, int> nda = new Nda<char, int>();
            nda.AddPattern("a|b*", 1);
            Assert.IsFalse(nda.Process("aba"));
            Assert.IsFalse(nda.Process("aab"));
            Assert.IsFalse(nda.Process("aa"));
            Assert.IsFalse(nda.Process("ab"));
            Assert.IsTrue(nda.Process("a"));
            Assert.AreEqual(1, nda.Value);
            Assert.IsTrue(nda.Process("b"));
            Assert.AreEqual(1, nda.Value);
            Assert.IsTrue(nda.Process("bb"));
            Assert.AreEqual(1, nda.Value);
            Assert.IsTrue(nda.Process(string.Empty));
            Assert.AreEqual(1, nda.Value);
            Assert.IsTrue(nda.Process((string)null));
            Assert.AreEqual(1, nda.Value);
        }

        [Test]
        public void AsocOrAnd()
        {
            Nda<char, int> nda = new Nda<char, int>();
            nda.AddPattern("(a|b)c", 1);
            Assert.IsFalse(nda.Process(string.Empty));
            Assert.IsFalse(nda.Process((string)null));
            Assert.IsFalse(nda.Process("a"));
            Assert.IsFalse(nda.Process("b"));
            Assert.IsFalse(nda.Process("c"));
            Assert.IsFalse(nda.Process("ab"));
            Assert.IsFalse(nda.Process("abc"));
            Assert.IsFalse(nda.Process("ca"));
            Assert.IsFalse(nda.Process("cb"));
            Assert.IsFalse(nda.Process("acc"));
            Assert.IsFalse(nda.Process("bcc"));
            Assert.IsTrue(nda.Process("ac"));
            Assert.AreEqual(1, nda.Value);
            Assert.IsTrue(nda.Process("bc"));
            Assert.AreEqual(1, nda.Value);
        }

        [Test]
        public void AsocOrAndAsocOr()
        {
            Nda<char, int> nda = new Nda<char, int>();
            nda.AddPattern("(a|b)(c|d)", 1);
            Assert.IsFalse(nda.Process(string.Empty));
            Assert.IsFalse(nda.Process((string)null));
            Assert.IsFalse(nda.Process("a"));
            Assert.IsFalse(nda.Process("b"));
            Assert.IsFalse(nda.Process("c"));
            Assert.IsFalse(nda.Process("d"));
            Assert.IsFalse(nda.Process("ab"));
            Assert.IsFalse(nda.Process("cd"));
            Assert.IsTrue(nda.Process("ac"));
            Assert.AreEqual(1, nda.Value);
            Assert.IsTrue(nda.Process("ad"));
            Assert.AreEqual(1, nda.Value);
            Assert.IsTrue(nda.Process("bc"));
            Assert.AreEqual(1, nda.Value);
            Assert.IsTrue(nda.Process("bd"));
            Assert.AreEqual(1, nda.Value);
        }

        [Test]
        public void AndAsocOr()
        {
            Nda<char, int> nda = new Nda<char, int>();
            nda.AddPattern("a(b|c)", 1);
            Assert.IsFalse(nda.Process(string.Empty));
            Assert.IsFalse(nda.Process((string)null));
            Assert.IsFalse(nda.Process("a"));
            Assert.IsFalse(nda.Process("b"));
            Assert.IsFalse(nda.Process("c"));
            Assert.IsFalse(nda.Process("bc"));
            Assert.IsFalse(nda.Process("abc"));
            Assert.IsFalse(nda.Process("ba"));
            Assert.IsFalse(nda.Process("ca"));
            Assert.IsFalse(nda.Process("aab"));
            Assert.IsFalse(nda.Process("aac"));
            Assert.IsTrue(nda.Process("ab"));
            Assert.AreEqual(1, nda.Value);
            Assert.IsTrue(nda.Process("ac"));
            Assert.AreEqual(1, nda.Value);
        }

        [Test]
        public void AsocAndMany()
        {
            Nda<char, int> nda = new Nda<char, int>();
            nda.AddPattern("(ab)*", 1);
            Assert.IsFalse(nda.Process("a"));
            Assert.IsFalse(nda.Process("b"));
            Assert.IsFalse(nda.Process("aab"));
            Assert.IsFalse(nda.Process("abb"));
            Assert.IsFalse(nda.Process("ba"));
            Assert.IsFalse(nda.Process("aba"));
            Assert.IsFalse(nda.Process("bab"));
            Assert.IsTrue(nda.Process("ab"));
            Assert.AreEqual(1, nda.Value);
            Assert.IsTrue(nda.Process("abab"));
            Assert.AreEqual(1, nda.Value);
            Assert.IsTrue(nda.Process("ababab"));
            Assert.AreEqual(1, nda.Value);
            Assert.IsTrue(nda.Process(string.Empty));
            Assert.AreEqual(1, nda.Value);
            Assert.IsTrue(nda.Process((string)null));
            Assert.AreEqual(1, nda.Value);
        }

        [Test]
        public void PatternsMany1()
        {
            Nda<char, int> nda = new Nda<char, int>();
            nda.AddPattern("a", 1);
            nda.AddPattern("b", 2);
            Assert.IsFalse(nda.Process(string.Empty));
            Assert.IsFalse(nda.Process((string)null));
            Assert.IsFalse(nda.Process("c"));
            Assert.IsFalse(nda.Process("ab"));
            Assert.IsFalse(nda.Process("ba"));
            Assert.IsTrue(nda.Process("a"));
            Assert.AreEqual(1, nda.Value);
            Assert.IsTrue(nda.Process("b"));
            Assert.AreEqual(2, nda.Value);
        }

        [Test]
        public void PatternsMany2()
        {
            Nda<char, int> nda = new Nda<char, int>();
            nda.AddPattern("a*", 1);
            nda.AddPattern("b*", 2);
            Assert.IsFalse(nda.Process("c"));
            Assert.IsFalse(nda.Process("ab"));
            Assert.IsFalse(nda.Process("ba"));
            Assert.IsTrue(nda.Process("a"));
            Assert.AreEqual(1, nda.Value);
            Assert.IsTrue(nda.Process("aa"));
            Assert.AreEqual(1, nda.Value);
            Assert.IsTrue(nda.Process("b"));
            Assert.AreEqual(2, nda.Value);
            Assert.IsTrue(nda.Process("bb"));
            Assert.AreEqual(2, nda.Value);
            Assert.IsTrue(nda.Process(string.Empty));
            Assert.AreEqual(1, nda.Value);
            Assert.IsTrue(nda.Process((string)null));
            Assert.AreEqual(1, nda.Value);
        }

        [Test]
        public void PatternsMany3()
        {
            Nda<char, int> nda = new Nda<char, int>();
            nda.AddPattern("abc*", 1);
            nda.AddPattern("abd*", 2);
            Assert.IsFalse(nda.Process(string.Empty));
            Assert.IsFalse(nda.Process((string)null));
            Assert.IsFalse(nda.Process("c"));
            Assert.IsFalse(nda.Process("ba"));
            Assert.IsFalse(nda.Process("abcd"));
            Assert.IsFalse(nda.Process("abdc"));
            Assert.IsTrue(nda.Process("ab"));
            Assert.AreEqual(1, nda.Value);
            Assert.IsTrue(nda.Process("abc"));
            Assert.AreEqual(1, nda.Value);
            Assert.IsTrue(nda.Process("abcc"));
            Assert.AreEqual(1, nda.Value);
            Assert.IsTrue(nda.Process("abd"));
            Assert.AreEqual(2, nda.Value);
            Assert.IsTrue(nda.Process("abdd"));
            Assert.AreEqual(2, nda.Value);
        }

        [Test]
        public void Corchetes()
        {
            Nda<char, int> nda = new Nda<char, int>();
            nda.AddPattern("abc*", 1);
            nda.AddPattern("abd*", 2);
            Assert.IsFalse(nda.Process(string.Empty));
            Assert.IsFalse(nda.Process((string)null));
        }

    }
}
